package service

import (
	"fmt"
	"github.com/pkg/errors"
	"mime/multipart"
	"strconv"
	"strings"
	"trpg-base/constants"
	"trpg-base/dto"
	"trpg-base/entity"
	common_constants "trpg-common/constants"
	common_dto "trpg-common/dto"
	"trpg-common/logger"
	"trpg-common/utils/collection_util"
	"trpg-common/utils/gorm_util"
	"trpg-common/utils/json_util"
	"trpg-common/utils/oss_util"
	"trpg-common/utils/snowflake_util"
	"trpg-common/utils/time_util"
)

type RoomService struct{}

func (RoomService) AddRoom(room entity.Room, cover *multipart.FileHeader, user common_dto.UserInfo) entity.Room {
	gorm_util.Transaction(func() {
		if room.LabelIds != "" {
			room.LabelIds += ","
		}
		room.Admin = user.Uid
		room.IsDeleted = common_constants.DeleteNo
		room.Creator = user.Uid
		room.Modifier = user.Uid
		room.GmtCreated = time_util.Now()
		room.GmtModified = time_util.Now()
		gorm_util.InsertUpdateOne(&room)
		coverUrl := ""
		if cover != nil {
			split := strings.Split(cover.Filename, ".")
			suffix := split[len(split)-1]
			coverPath := fmt.Sprintf("/room/%d/cover.%s", room.Id, suffix)
			room.CoverKey = coverPath
			coverUrl = oss_util.UploadMultiFile(cover, coverPath)
		} else {
			coverUrl = oss_util.GetUrlByKey(defaultCoverKey)
		}
		room.CoverUrl = coverUrl
		gorm_util.UpdateOneByCondition(&room)
		// 写room_user表
		roomUser := entity.RoomUser{}
		roomUser.IsDeleted = common_constants.DeleteNo
		roomUser.Creator = user.Uid
		roomUser.Modifier = user.Uid
		roomUser.GmtCreated = time_util.Now()
		roomUser.GmtModified = time_util.Now()
		roomUser.RoomId = room.Id
		roomUser.Uid = user.Uid
		roomUser.Status = constants.ROOM_ADMIN
		gorm_util.InsertUpdateOne(&roomUser)
	})
	return room
}

func (RoomService) UpdateRoom(room entity.Room, cover *multipart.FileHeader, user common_dto.UserInfo) entity.Room {
	gorm_util.Transaction(func() {
		// 先去查原始数据
		oldRoom := entity.Room{}
		oldRoom.Id = room.Id
		gorm_util.SelectOneByCondition(&oldRoom)
		if user.Uid != oldRoom.Admin && user.Uid != oldRoom.Creator {
			logger.Logger.Panicf("%v", errors.New("不是房间管理员，无权修改"))
		}
		if room.LabelIds != "" {
			room.LabelIds += ","
		}
		room.Modifier = user.Uid
		room.GmtModified = time_util.Now()
		coverUrl := ""
		if cover != nil {
			split := strings.Split(cover.Filename, ".")
			suffix := split[len(split)-1]
			coverPath := fmt.Sprintf("/room/%d/cover.%s", room.Id, suffix)
			coverUrl = oss_util.UploadMultiFile(cover, coverPath)
		} else {
			coverUrl = oss_util.GetUrlByKey(defaultCoverKey)
		}
		room.CoverUrl = coverUrl
		gorm_util.UpdateOneByCondition(&room)
		// 如果修改了管理员
		if room.Admin != oldRoom.Admin {
			// 写room_user表
			oldAdmin := entity.RoomUser{}
			oldAdmin.RoomId = room.Id
			oldAdmin.Uid = oldRoom.Admin
			oldAdmin.IsDeleted = common_constants.DeleteNo
			gorm_util.SelectOneByCondition(&oldAdmin)
			oldAdmin.Status = constants.ROOM_MEMBER
			oldAdmin.Modifier = user.Uid
			oldAdmin.GmtModified = time_util.Now()
			gorm_util.InsertUpdateOne(&oldAdmin)
			newAdmin := entity.RoomUser{}
			newAdmin.RoomId = room.Id
			newAdmin.Uid = room.Admin
			newAdmin.IsDeleted = common_constants.DeleteNo
			gorm_util.SelectOneByCondition(&newAdmin)
			newAdmin.Status = constants.ROOM_ADMIN
			newAdmin.Modifier = user.Uid
			newAdmin.GmtModified = time_util.Now()
			gorm_util.InsertUpdateOne(&newAdmin)
		}
	})
	return room
}

func (RoomService) SearchRooms(search dto.RoomRequest, request gorm_util.PageRequest, user common_dto.UserInfo) *gorm_util.PageResult {
	paramBuilder := gorm_util.NewParamBuilder().Model(&entity.Room{}).Eq("is_deleted", common_constants.DeleteNo)
	if search.Search != "" {
		paramBuilder.Or(gorm_util.NewParamBuilder().Like("name", `%`+search.Search+`%`), gorm_util.NewParamBuilder().Like("description", `%`+search.Search+`%`))
	}
	if search.Created == true {
		paramBuilder.Eq("creator", user.Uid)
	} else if search.Joined == true {
		collections := make([]entity.RoomUser, 0)
		gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("uid", user.Uid).Eq("is_deleted", common_constants.DeleteNo).Eq("status", constants.ROOM_MEMBER), &collections)
		collectionIds := make([]int64, 0, len(collections))
		for _, collection := range collections {
			collectionIds = append(collectionIds, collection.RoomId)
		}
		paramBuilder.In("id", collectionIds)
	} else if search.Managed == true {
		collections := make([]entity.RoomUser, 0)
		gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("uid", user.Uid).Eq("is_deleted", common_constants.DeleteNo).Eq("status", constants.ROOM_ADMIN), &collections)
		collectionIds := make([]int64, 0, len(collections))
		for _, collection := range collections {
			collectionIds = append(collectionIds, collection.RoomId)
		}
		paramBuilder.In("id", collectionIds)
	}
	if search.LabelIds != nil && len(search.LabelIds) != 0 {
		paramSlice := make([]*gorm_util.ParamBuilder, 0, len(search.LabelIds))
		for _, labelId := range search.LabelIds {
			paramSlice = append(paramSlice, gorm_util.NewParamBuilder().Like("label_ids", `%`+strconv.FormatInt(labelId, 10)+`,%`))
		}
		paramBuilder.Or(paramSlice...)
	}
	if search.BeginTime != nil && search.EndTime != nil {
		paramBuilder.Gte("gmt_created", search.BeginTime).Lte("gmt_created", search.EndTime)
	}
	rooms := make([]entity.Room, 0)
	result := gorm_util.PageSelectByParamBuilder(paramBuilder, &rooms, request)
	for i, _ := range rooms {
		rooms[i].CoverUrl = oss_util.GetUrlByKey(rooms[i].CoverKey)
		// 处理label
		labelIds := make([]int64, 0)
		for _, str := range strings.Split(rooms[i].LabelIds, ",") {
			if str == "" {
				continue
			}
			labelId, _ := strconv.ParseInt(str, 10, 64)
			labelIds = append(labelIds, labelId)
		}
		rooms[i].LabelIdsArr = labelIds
		rooms[i].LabelNames = labelService.GetLabelNameListByIds(labelIds)
		if rooms[i].Creator == user.Uid {
			rooms[i].IsCreator = true
		}
		if rooms[i].Admin == user.Uid {
			rooms[i].IsAdmin = true
		}
		// 判断是否是房间成员
		member := entity.RoomUser{}
		member.RoomId = rooms[i].Id
		member.Uid = user.Uid
		member.IsDeleted = common_constants.DeleteNo
		gorm_util.SelectOneByCondition(&member)
		if member.Id != 0 {
			rooms[i].IsMember = true
			rooms[i].CharacterId = member.CharacterId
		}
	}
	result.List = rooms
	return result
}

func (RoomService) BindCharacter(roomId int64, characterId int64, user common_dto.UserInfo) {
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("room_id", roomId).Eq("uid", user.Uid).Eq("is_deleted", common_constants.DeleteNo),
		map[string]interface{}{
			"character_id": characterId,
		})
}

func (RoomService) BindScript(roomId int64, scriptId int64, user common_dto.UserInfo) {
	roomUser := entity.RoomUser{
		RoomId: roomId,
		Uid:    user.Uid,
	}
	roomUser.IsDeleted = common_constants.DeleteNo
	gorm_util.SelectOneByCondition(&roomUser)
	room := entity.Room{}
	room.Id = roomId
	room.IsDeleted = common_constants.DeleteNo
	gorm_util.SelectOneByCondition(&room)
	if roomUser.Status != constants.ROOM_ADMIN && room.Creator != user.Uid {
		logger.Logger.Panicf("%+v", errors.New("不是管理员，无权操作"))
	}
	room.BindScriptId = scriptId
	room.Modifier = user.Uid
	room.GmtModified = time_util.Now()
	gorm_util.InsertUpdateOne(&room)
}

func (RoomService) ApplyJoinRoom(room entity.Room, user common_dto.UserInfo) {
	// 写room_user表
	roomUser := entity.RoomUser{}
	roomUser.IsDeleted = common_constants.DeleteNo
	roomUser.Creator = user.Uid
	roomUser.Modifier = user.Uid
	roomUser.GmtCreated = time_util.Now()
	roomUser.GmtModified = time_util.Now()
	roomUser.RoomId = room.Id
	roomUser.Uid = user.Uid
	roomUser.Status = constants.ROOM_JOINER
	gorm_util.InsertUpdateOne(&roomUser)
	// 查询管理员
	admin := entity.RoomUser{}
	admin.RoomId = room.Id
	admin.IsDeleted = common_constants.DeleteNo
	admin.Status = constants.ROOM_ADMIN
	gorm_util.SelectOneByCondition(&admin)
	// 写消息表
	systemMessageService.SendMessage(fmt.Sprintf("%s(用户id:%s)想要加入您管理的房间{%s}，请到房间管理页面处理", user.Username, user.Uid, room.Name), admin.Uid)
}

func (RoomService) DealApply(room entity.Room, uid string, flag bool, user common_dto.UserInfo) {
	paramBuilder := gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("room_id", room.Id).Eq("uid", uid).Eq("is_deleted", common_constants.DeleteNo)
	if flag {
		// 同意
		gorm_util.UpdateBatchByParamBuilderAndMap(
			paramBuilder,
			map[string]interface{}{
				"status":       constants.ROOM_MEMBER,
				"modifier":     user.Uid,
				"gmt_modified": time_util.Now(),
			})
		// 写系统消息表
		systemMessageService.SendMessage(fmt.Sprintf("房间{%s}的管理员同意了您的加入申请", room.Name), uid)
	} else {
		// 同意
		gorm_util.UpdateBatchByParamBuilderAndMap(
			paramBuilder,
			map[string]interface{}{
				"is_deleted":   common_constants.DeleteYes,
				"modifier":     user.Uid,
				"gmt_modified": time_util.Now(),
			})
		// 写系统消息表
		systemMessageService.SendMessage(fmt.Sprintf("房间{%s}的管理员拒绝了您的加入申请", room.Name), uid)
	}
}

func (RoomService) DeleteMembers(room entity.Room, uid string, username string, user common_dto.UserInfo) {
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("room_id", room.Id).Eq("uid", uid),
		map[string]interface{}{
			"is_deleted":   common_constants.DeleteYes,
			"modifier":     uid,
			"gmt_modified": time_util.Now(),
		},
	)
	// 发送系统消息
	systemMessageService.SendMessage(fmt.Sprintf("管理员将您从房间{%s}移除", room.Name), uid)
	systemMessageService.SendMessage(fmt.Sprintf("您作为管理员将用户{%s}从房间{%s}中移除", username, room.Name), user.Uid)
}

func (RoomService) QuitRoom(room entity.Room, user common_dto.UserInfo) {
	gorm_util.UpdateBatchByParamBuilderAndMap(
		gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("room_id", room.Id).Eq("uid", user.Uid),
		map[string]interface{}{
			"is_deleted":   common_constants.DeleteYes,
			"modifier":     user.Uid,
			"gmt_modified": time_util.Now(),
		},
	)
	// 发送系统消息
	systemMessageService.SendMessage(fmt.Sprintf("您从房间{%s}中退出", room.Name), user.Uid)
	systemMessageService.SendMessage(fmt.Sprintf("用户{%s}从您管理的房间{%s}中退出", user.Username, room.Name), room.Admin)
}

func (RoomService) GetRoomDetail(id int64, user common_dto.UserInfo) entity.Room {
	room := entity.Room{}
	room.Id = id
	room.IsDeleted = common_constants.DeleteNo
	gorm_util.SelectOneByCondition(&room)
	if room.CoverKey == "" {
		room.CoverUrl = oss_util.GetUrlByKey(defaultCoverKey)
	} else {
		room.CoverUrl = oss_util.GetUrlByKey(room.CoverKey)
	}
	// 处理label
	labelIds := make([]int64, 0)
	for _, str := range strings.Split(room.LabelIds, ",") {
		if str == "" {
			continue
		}
		labelId, _ := strconv.ParseInt(str, 10, 64)
		labelIds = append(labelIds, labelId)
	}
	room.LabelIdsArr = labelIds
	room.LabelNames = labelService.GetLabelNameListByIds(labelIds)
	roomUser := entity.RoomUser{}
	roomUser.RoomId = id
	roomUser.Uid = user.Uid
	roomUser.IsDeleted = common_constants.DeleteNo
	gorm_util.SelectOneByCondition(&roomUser)
	if roomUser.Status == constants.ROOM_ADMIN {
		room.IsAdmin = true
	} else {
		room.CharacterId = roomUser.CharacterId
	}
	return room
}

func (RoomService) GetMembers(roomId int64) []common_dto.CodeEnumDTO {
	roomUsers := make([]entity.RoomUser, 0)
	gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.RoomUser{}).Eq("room_id", roomId).Eq("is_deleted", common_constants.DeleteNo), &roomUsers)
	uidList := make([]string, 0, len(roomUsers))
	for _, roomUser := range roomUsers {
		uidList = append(uidList, roomUser.Uid)
	}
	userIdNameMap := userService.GetUserIdNameMapByUidList(uidList)
	res := make([]common_dto.CodeEnumDTO, 0, len(userIdNameMap))
	for _, roomUser := range roomUsers {
		res = append(res, common_dto.CodeEnumDTO{
			Label: userIdNameMap[roomUser.Uid],
			Value: map[string]interface{}{
				"uid":    roomUser.Uid,
				"status": roomUser.Status,
			},
			Disabled: false,
		})
	}
	return res
}

func (RoomService) SendMessageFiles(roomId int64, file *multipart.FileHeader) (string, string) {
	split := strings.Split(file.Filename, ".")
	suffix := split[len(split)-1]
	filePath := fmt.Sprintf("/room/%d/%d.%s", roomId, snowflake_util.SnowFlakeID(), suffix)
	return oss_util.UploadMultiFile(file, filePath), filePath
}

func (RoomService) GetRoomMessages(roomId int64) []entity.RoomMessage {
	res := make([]entity.RoomMessage, 0)
	gorm_util.SelectByParamBuilder(gorm_util.NewParamBuilder().Model(&entity.RoomMessage{}).Eq("room_id", roomId).OrderByDesc("gmt_created").Limit(100), &res)
	userSet := collection_util.NewSet[string]()
	for _, msg := range res {
		userSet.Add(msg.Creator)
	}
	m := userService.GetUserMapByUidList(userSet.ToSlice())
	for i, _ := range res {
		res[i].CreatorName = m[res[i].Creator].Username
		res[i].Avatar = m[res[i].Creator].Avatar
		split := strings.Split(res[i].GmtCreated.ToString(), " ")
		res[i].Date = split[0]
		res[i].TimeStamp = split[1]
		msg := res[i]
		if msg.FilesStr != "" {
			msg.Files = make([]entity.File, 0)
			json_util.UnMarshal([]byte(msg.FilesStr), &(msg.Files))
			for j, _ := range msg.Files {
				msg.Files[j].Url = oss_util.GetUrlByKey(msg.Files[j].Path)
			}
		}
		res[i] = msg
	}
	return res
}
